package com.zusmart.base.activity.support;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.zusmart.base.activity.Activity;
import com.zusmart.base.activity.ActivityListener;
import com.zusmart.base.logging.Logger;
import com.zusmart.base.logging.LoggerFactory;

public abstract class AbstractActivity<A extends Activity<A>> implements Activity<A> {

	private static final Logger logger = LoggerFactory.getLogger(AbstractActivity.class);

	private static final byte T_FAILED = -1;
	private static final byte T_STARTED = 0;
	private static final byte T_STOPPED = 1;
	private static final byte T_STARTING = 2;
	private static final byte T_STOPPING = 3;

	private volatile byte state = T_STOPPED;

	private List<ActivityListener<A>> listeners = new ArrayList<ActivityListener<A>>();

	@Override
	public synchronized void start() throws Exception {
		if (!this.isRunning()) {
			this.state = T_STARTING;
			this.fireEvent(T_STARTING, null);
			try {
				this.doStart();
			} catch (Exception e) {
				this.state = T_FAILED;
				this.fireEvent(T_FAILED, e);
				throw e;
			}
			this.state = T_STARTED;
			this.fireEvent(T_STARTED, null);
		}
	}

	@Override
	public synchronized void close() throws Exception {
		if (this.isRunning()) {
			this.state = T_STOPPING;
			this.fireEvent(T_STOPPING, null);
			try {
				this.wakeup();
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
			try {
				this.doClose();
			} catch (Exception e) {
				e.printStackTrace();
				logger.error(e.getMessage(), e);
			}
			this.state = T_STOPPED;
			this.fireEvent(T_STOPPED, null);
		}
	}

	@Override
	public void addListener(ActivityListener<A> listener) {
		synchronized (this) {
			if (this.isRunning() || null == listener) {
				return;
			}
			this.listeners.add(listener);
			Collections.sort(this.listeners);
		}
	}

	@Override
	public void delListener(ActivityListener<A> listener) {
		synchronized (this) {
			if (this.isRunning() || null == listener) {
				return;
			}
			this.listeners.remove(listener);
			Collections.sort(this.listeners);
		}
	}

	@Override
	public boolean isRunning() {
		return this.state == T_STARTED;
	}

	@Override
	public boolean isFailed() {
		return this.state == T_FAILED;
	}

	@Override
	public boolean isStopped() {
		return this.state == T_STOPPED;
	}

	@Override
	public boolean isStarting() {
		return this.state == T_STARTING;
	}

	@Override
	public boolean isStopping() {
		return this.state == T_STOPPING;
	}

	public void wakeup() {
		// IGNORE
	}

	protected void fireEvent(byte event, Exception exception) {
		if (this.listeners.size() == 0) {
			return;
		}
		A activity = this.getActivity();
		if (event == T_STARTING) {
			for (ActivityListener<A> listener : this.listeners) {
				try {
					listener.onStarting(activity);
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
				}
			}
		} else if (event == T_STARTED) {
			for (ActivityListener<A> listener : this.listeners) {
				try {
					listener.onStarted(activity);
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
				}
			}
		} else if (event == T_STOPPED) {
			for (ActivityListener<A> listener : this.listeners) {
				try {
					listener.onStopped(activity);
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
				}
			}
		} else if (event == T_STOPPING) {
			for (ActivityListener<A> listener : this.listeners) {
				try {
					listener.onStopping(activity);
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
				}
			}
		} else if (event == T_FAILED) {
			for (ActivityListener<A> listener : this.listeners) {
				try {
					listener.onFailed(activity, exception);
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
				}
			}
		}
	}

	protected abstract A getActivity();

	protected abstract void doStart() throws Exception;

	protected abstract void doClose() throws Exception;

}